package com.draven.util;

import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.Tika;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * MinIO工具类
 */
@Slf4j
@Component
public class MinioUtil {

    @Autowired
    private MinioClient minioClient;

    @Value("${minio.bucketName}")
    private String bucketName;

    @Value("${minio.endpoint}")
    private String endpoint;

    /**
     * 上传文件
     * @param file 文件
     * @param directory 目录
     * @return 文件信息
     */
    public Map<String, Object> uploadFile(MultipartFile file, String directory) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 生成文件名
            String originalFilename = file.getOriginalFilename();
            String fileName = generateFileName(originalFilename);
            String objectName = directory + "/" + fileName;
            
            // 获取文件类型
            String contentType = determineContentType(file);
            
            // 上传文件
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .contentType(contentType)
                            .build()
            );
            
            // 生成访问URL
            String fileUrl = getFileUrl(objectName, 7); // 7天有效期
            
            result.put("originalName", originalFilename);
            result.put("fileName", fileName);
            result.put("filePath", objectName);
            result.put("fileUrl", fileUrl);
            result.put("fileType", contentType);
            result.put("fileSize", file.getSize());
            
            return result;
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }

    /**
     * 上传缩略图
     * @param inputStream 输入流
     * @param size 文件大小
     * @param objectName 对象名称
     * @return 缩略图URL
     */
    public String uploadThumbnail(InputStream inputStream, long size, String objectName) {
        try {
            String thumbnailName = "thumbnail/" + objectName;
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(thumbnailName)
                            .stream(inputStream, size, -1)
                            .contentType("image/jpeg")
                            .build()
            );
            return getFileUrl(thumbnailName, 7); // 7天有效期
        } catch (Exception e) {
            log.error("缩略图上传失败", e);
            return null;
        }
    }

    /**
     * 获取文件
     * @param objectName 对象名称
     * @return 输入流
     */
    public InputStream getFile(String objectName) {
        try {
            return minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build()
            );
        } catch (Exception e) {
            log.error("获取文件失败", e);
            throw new RuntimeException("获取文件失败: " + e.getMessage());
        }
    }

    /**
     * 获取文件URL
     * @param objectName 对象名称
     * @param expiry 过期时间（天）
     * @return 文件URL
     */
    public String getFileUrl(String objectName, int expiry) {
        try {
            return minioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(bucketName)
                            .object(objectName)
                            .expiry(expiry, TimeUnit.DAYS)
                            .build()
            );
        } catch (Exception e) {
            log.error("获取文件URL失败", e);
            throw new RuntimeException("获取文件URL失败: " + e.getMessage());
        }
    }

    /**
     * 删除文件
     * @param objectName 对象名称
     */
    public void deleteFile(String objectName) {
        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build()
            );
            
            // 删除缩略图（如果存在）
            try {
                minioClient.removeObject(
                        RemoveObjectArgs.builder()
                                .bucket(bucketName)
                                .object("thumbnail/" + objectName)
                                .build()
                );
            } catch (Exception e) {
                log.warn("删除缩略图失败，可能不存在: {}", e.getMessage());
            }
        } catch (Exception e) {
            log.error("删除文件失败", e);
            throw new RuntimeException("删除文件失败: " + e.getMessage());
        }
    }

    /**
     * 判断文件是否存在
     * @param objectName 对象名称
     * @return 是否存在
     */
    public boolean isFileExist(String objectName) {
        try {
            minioClient.statObject(
                    StatObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build()
            );
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 生成文件名
     * @param originalFilename 原始文件名
     * @return 生成的文件名
     */
    private String generateFileName(String originalFilename) {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        int index = originalFilename.lastIndexOf(".");
        if (index != -1) {
            String extension = originalFilename.substring(index);
            return uuid + extension;
        }
        return uuid;
    }

    /**
     * 确定文件类型
     * @param file 文件
     * @return 文件类型
     */
    private String determineContentType(MultipartFile file) {
        Tika tika = new Tika();
        try {
            return tika.detect(file.getInputStream());
        } catch (IOException e) {
            log.warn("无法检测文件类型，使用默认类型", e);
            return file.getContentType();
        }
    }
} 